/*
 * Copyright (C) 2010 Rodion Volkov (volkov.rodion@gmail.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.rchik.divermate;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLDecoder;
import java.util.HashMap;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.ContentBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import org.json.JSONObject;

import android.app.ProgressDialog;
import android.content.Context;
import android.util.Log;

import com.rchik.divermate.FacebookPhotoUploadListener.ErrorCodes;

public class FacebookPhotoUploader {
	
	private Facebook facebook;	
	private FacebookPhotoUploadListener listener;
	private AsyncFacebookRunner runner;
	private String storedAlbumName;
	private InputStream storedImageStream;
	private String storedCaption;
	private long storedStreamLength;
	private Context context;
	private String APP_ID;
	private HashMap<String,String> albumNameIdPairs;
	private PhotoUploadProgressDialog progressDialog;
	
	public FacebookPhotoUploader(Context context) 
	{
		this.context = context;
		facebook = new Facebook();
		runner = new AsyncFacebookRunner(facebook);
		
		albumNameIdPairs = new HashMap<String, String>();
	}
	
	public void setAPP_ID(String aPPID) {
		APP_ID = aPPID;
	}

	public void setFacebook(Facebook facebook) {
		this.facebook = facebook;
		
		runner = new AsyncFacebookRunner( facebook );
	}
	
	public AsyncFacebookRunner getRunner()
	{
		return runner;
	}
	
	public Facebook getFacebook() {
		return facebook;
	}
	
	public void setListener(FacebookPhotoUploadListener listener) {
		this.listener = listener;
	}
	
	public FacebookPhotoUploadListener getListener() {
		return listener;
	}
	
	public void uploadPhoto(PhotoUploadProgressDialog dialog, InputStream imageStream, long streamLength, String albumName, String caption)
	{
		if ( listener == null )
		{
			Log.e("FacebookPhotoUploader", "Eror - no listener! Upload failed");
			return;
		}
		
		storedAlbumName = albumName;
		storedCaption = caption;
		storedImageStream = imageStream;
		storedStreamLength = streamLength;
		
		if ( dialog == null )
		{
			progressDialog = new PhotoUploadProgressDialog(context, 
						context.getString(R.string.please_wait), 
						context.getString(R.string.searching_album)
						.replace("%album%", albumName));
			
			progressDialog.show();
		}
		else
		{
			progressDialog = dialog;
			
			progressDialog.setMessageText(context.getString(R.string.searching_album).replace("%album%", storedAlbumName));
		}		
		
		if ( facebook.getAccessToken() != null)
		{
			String albumId = albumNameIdPairs.get(albumName);
			if ( albumId != null)
			{
				photoPost();
			}
			else
			{
				findOrCreateAlbum();
			}
		}
		else
		{
			authenticateAndPost();
		}
	}

	public void findOrCreateAlbum() {
		runner.request("me/albums",new PhotoUploadAlbumListListener(this
				, progressDialog));
	}

	private void authenticateAndPost() {
		facebook.authorize(context, APP_ID
		, new String[]{"user_photos","publish_stream"}
		, new PhotoUploadAuthListener(this, progressDialog));
	}
	
	@SuppressWarnings("unused")
	private byte[] getBytesFromFile() {
		
		File file = new File("/sdcard/device.png");
		
		try
        {		
	        FileInputStream is = new FileInputStream(file);
	    
	        // Get the size of the file
	        long length = file.length();
	    
	        if (length > Integer.MAX_VALUE) {
	            listener.onPhotoUploadFailed(ErrorCodes.ErrorFileIsTooLarge, "File is too large");
	            
	            return null;
	        }
	    
	        // Create the byte array to hold the data
	        byte[] bytes = new byte[(int)length];
	    
        
	        // Read in the bytes
	        int offset = 0;
	        int numRead = 0;
	        while (offset < bytes.length
	               && (numRead=is.read(bytes, offset, bytes.length-offset)) >= 0) {
	            offset += numRead;
	        }
        
        
	        // Ensure all the bytes have been read in
	        if (offset < bytes.length) {
	            listener.onPhotoUploadFailed(ErrorCodes.ErrorFileLoadFailed,"Could not completely read file "+file.getName());
	            
	            return null;
	        }
        
	        // Close the input stream and return bytes
	        is.close();
	        
	        return bytes;
        
        }
        catch ( IOException e )
        {
        	listener.onPhotoUploadFailed(ErrorCodes.ErrorFileLoadFailed,"Exception "+e.getMessage());
        	
        	return null;
        }
    }

	@SuppressWarnings("unused")
	private byte[] getBytesFromStream(InputStream stream) {
		
		try
        {			
			int tempByte;
			
			ByteArrayOutputStream baos = new ByteArrayOutputStream();
			
			while ( (tempByte = stream.read()) > 0 )
			{
				baos.write(tempByte);
			}
			
			return baos.toByteArray();
        
        }
        catch ( Exception e )
        {
        	listener.onPhotoUploadFailed(ErrorCodes.ErrorFileLoadFailed,"Exception "+e.getMessage());
        	
        	return null;
        }
    }
	
	public void photoPost() 
	{
		progressDialog.setMessageText(context.getText(R.string.posting_photo));
				
//		byte[] fileBytes = getBytesFromFile();//Stream(storedImageStream);
//		
//		if ( fileBytes != null )
//		{
//			Bundle params = new Bundle();
//			
//            //params.putString("method", "photos.upload");
//            params.putString("message", storedCaption);
//            //params.putString("aid", albumNameIdPairs.get(storedAlbumName));
//            params.putByteArray("source", fileBytes);
//            
//            runner.request(albumNameIdPairs.get(storedAlbumName)+"/photos", params, "POST", 
//        			new PhotoUploadRequestListener(this, progressDialog));
//		}
		try
		{
			HttpClient httpclient = new DefaultHttpClient();
	    	
		    httpclient.getParams().setParameter( CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1 );
		    
		    HttpPost httppost = new HttpPost( "https://graph.facebook.com/"+albumNameIdPairs.get(storedAlbumName)+"/photos" );
		    
		    //File file = new File( "/sdcard/device.png" );
		
		    MultipartEntity mpEntity  = new MultipartEntity( HttpMultipartMode.STRICT );
		    ContentBody cbFile        = new LimitedInputStreamBody(storedImageStream, storedStreamLength);//FileBody( file, "image/png" );
		    ContentBody cbMessage     = new StringBody( storedCaption );
		    ContentBody cbAccessToken = new StringBody( URLDecoder.decode(facebook.getAccessToken()) );
		
		    mpEntity.addPart( "access_token", cbAccessToken );
		    mpEntity.addPart( "message",      cbMessage     );
		    mpEntity.addPart( "source",       cbFile        );
		    
		    httppost.setEntity(mpEntity);
		    
		    HttpResponse response = httpclient.execute( httppost );
		    HttpEntity resEntity = response.getEntity( );
		    String entityString = EntityUtils.toString( resEntity );
		
		    // DEBUG
		    System.out.println( response.getStatusLine( ) );
		    if (resEntity != null) {
		    	
		      System.out.println( entityString );
		    }
		    
		    progressDialog.dismiss();
		    
		    JSONObject json = new JSONObject(entityString);
		    String id = (String)json.getString("id");
		    
		    listener.onPhotoUploadSuccess(id);
		}
		catch (Exception e)
		{
			progressDialog.dismiss();
			listener.onPhotoUploadFailed(ErrorCodes.ErrorPostImageFailed, e.getMessage());
		}
	}
	
	public Context getContext() {
		return context;
	}

	public void setAlbumNameIdPairs(HashMap<String,String> albumNameIdPairs) {
		this.albumNameIdPairs = albumNameIdPairs;
	}

	public HashMap<String,String> getAlbumNameIdPairs() {
		return albumNameIdPairs;
	}

	public String getStoredAlbumName() {
		return storedAlbumName;
	}

	public ProgressDialog getProgressDialog() {
		return progressDialog;
	}
}
